{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook demostrates the core functionality of pymatgen, including the core objects representing Elements, Species, Lattices, and Structures. \n",
    "\n",
    "By convention, we import pymatgen as mg."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import pymatgen as mg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Element, Specie and Composition objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pymatgen contains a set of core classes to represent an Element, Specie and Composition. These objects contains useful properties such as atomic mass, ionic radii, etc. These core classes are loaded by default with pymatgen. An Element can be created as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Atomic mass of Si is 28.0855 amu\n",
      "Si has a melting point of 1687 K\n",
      "Ionic radii for Si: {4: 0.54}\n"
     ]
    }
   ],
   "source": [
    "si = mg.Element(\"Si\")\n",
    "print(\"Atomic mass of Si is {}\".format(si.atomic_mass))\n",
    "print(\"Si has a melting point of {}\".format(si.melting_point))\n",
    "print(\"Ionic radii for Si: {}\".format(si.ionic_radii))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see that units are printed for atomic masses and ionic radii. Pymatgen comes with a complete system of managing units in pymatgen.core.unit. A Unit is a subclass of float that attaches units and handles conversions. For example,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Atomic mass of Si in kg: 4.66370658657e-26 kg\n"
     ]
    }
   ],
   "source": [
    "print(\"Atomic mass of Si in kg: {}\".format(si.atomic_mass.to(\"kg\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Please refer to the Units example for more information on units. Species are like Elements, except they have an explicit oxidation state. They can be used wherever Element is used for the most part."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "55.845 amu\n",
      "0.92 ang\n"
     ]
    }
   ],
   "source": [
    "fe2 = mg.Specie(\"Fe\", 2)\n",
    "print(fe2.atomic_mass)\n",
    "print(fe2.ionic_radius)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A Composition is essentially an **immutable** mapping of Elements/Species with amounts, and useful properties like molecular weight, get_atomic_fraction, etc. Note that you can conveniently either use an Element/Specie object or a string as keys (this is a feature)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Weight of Fe2O3 is 159.6882 amu\n",
      "Amount of Fe in Fe2O3 is 2.0\n",
      "Atomic fraction of Fe is 0.4\n",
      "Weight fraction of Fe is 0.699425505454 \n"
     ]
    }
   ],
   "source": [
    "comp = mg.Composition(\"Fe2O3\")\n",
    "print(\"Weight of Fe2O3 is {}\".format(comp.weight))\n",
    "print(\"Amount of Fe in Fe2O3 is {}\".format(comp[\"Fe\"]))\n",
    "print(\"Atomic fraction of Fe is {}\".format(comp.get_atomic_fraction(\"Fe\")))\n",
    "print(\"Weight fraction of Fe is {}\".format(comp.get_wt_fraction(\"Fe\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lattice & Structure objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A Lattice represents a Bravais lattice. Convenience static functions are provided for the creation of common lattice types from a minimum number of arguments. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "((4.2000000000000002, 4.2000000000000002, 4.2000000000000002), (90.0, 90.0, 90.0))\n"
     ]
    }
   ],
   "source": [
    "# Creates cubic Lattice with lattice parameter 4.2\n",
    "lattice = mg.Lattice.cubic(4.2)\n",
    "print(lattice.lengths_and_angles)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A Structure object represents a crystal structure (lattice + basis). A Structure is essentially a list of PeriodicSites with the same Lattice. Let us now create a CsCl structure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Unit cell vol = 74.088\n",
      "First site of the structure is [ 0.  0.  0.] Cs\n"
     ]
    }
   ],
   "source": [
    "structure = mg.Structure(lattice, [\"Cs\", \"Cl\"], [[0, 0, 0], [0.5, 0.5, 0.5]])\n",
    "print(\"Unit cell vol = {}\".format(structure.volume))\n",
    "print(\"First site of the structure is {}\".format(structure[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Structure object contains many useful manipulation functions. Since Structure is essentially a list, it contains a simple pythonic API for manipulation its sites. Some examples are given below. Please note that there is an immutable version of Structure known as IStructure, for the use case where you really need to enforce that the structure does not change. Conversion between these forms of Structure can be performed using from_sites()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Structure Summary (Cs3 Li1 Cl4)\n",
      "Reduced Formula: Cs3LiCl4\n",
      "abc   :   8.400000   8.400000   4.200000\n",
      "angles:  90.000000  90.000000  90.000000\n",
      "Sites (8)\n",
      "1 Cs     0.010000     0.500000     0.000000\n",
      "2 Cs     0.500000     0.000000     0.000000\n",
      "3 Cs     0.500000     0.500000     0.000000\n",
      "4 Cl     0.250000     0.250000     0.500000\n",
      "5 Cl     0.250000     0.750000     0.500000\n",
      "6 Cl     0.750000     0.250000     0.500000\n",
      "7 Cl     0.750000     0.750000     0.500000\n",
      "8 Li     0.000000     0.000000     0.000000\n"
     ]
    }
   ],
   "source": [
    "structure.make_supercell([2, 2, 1]) #Make a 3 x 2 x 1 supercell of the structure\n",
    "del structure[0] #Remove the first site\n",
    "structure.append(\"Na\", [0,0,0]) #Append a Na atom.\n",
    "structure[-1] = \"Li\" #Change the last added atom to Li.\n",
    "structure[0] = \"Cs\", [0.01, 0.5, 0] #Shift the first atom by 0.01 in fractional coordinates in the x-direction.\n",
    "immutable_structure = mg.IStructure.from_sites(structure) #Create an immutable structure (cannot be modified).\n",
    "print(immutable_structure)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic analyses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pymatgen provides many analyses functions for Structures. Some common ones are given below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The spacegroup is P2mm\n"
     ]
    }
   ],
   "source": [
    "#Determining the symmetry\n",
    "from pymatgen.symmetry.analyzer import SpacegroupAnalyzer\n",
    "finder = SpacegroupAnalyzer(structure)\n",
    "print(\"The spacegroup is {}\".format(finder.get_spacegroup_symbol()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We also have an extremely powerful structure matching tool."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "from pymatgen.analysis.structure_matcher import StructureMatcher\n",
    "#Let's create two structures which are the same topologically, but with different elements, and one lattice is larger.\n",
    "s1 = mg.Structure(lattice, [\"Cs\", \"Cl\"], [[0, 0, 0], [0.5, 0.5, 0.5]])\n",
    "s2 = mg.Structure(mg.Lattice.cubic(5), [\"Rb\", \"F\"], [[0, 0, 0], [0.5, 0.5, 0.5]])\n",
    "m = StructureMatcher()\n",
    "print(m.fit_anonymous(s1, s2)) #Returns a mapping which maps s1 and s2 onto each other. Strict element fitting is also available."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Input/output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pymatgen also provides IO support for various file formats in the pymatgen.io package. A convenient set of read_structure and write_structure functions are also provided which auto-detects several well-known formats. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cs3 Li1 Cl4\n",
      "1.0\n",
      "8.400000 0.000000 0.000000\n",
      "0.000000 8.400000 0.000000\n",
      "0.000000 0.000000 4.200000\n",
      "Cs Cl Li\n",
      "3 4 1\n",
      "direct\n",
      "0.010000 0.500000 0.000000 Cs\n",
      "0.500000 0.000000 0.000000 Cs\n",
      "0.500000 0.500000 0.000000 Cs\n",
      "0.250000 0.250000 0.500000 Cl\n",
      "0.250000 0.750000 0.500000 Cl\n",
      "0.750000 0.250000 0.500000 Cl\n",
      "0.750000 0.750000 0.500000 Cl\n",
      "0.000000 0.000000 0.000000 Li\n",
      "\n",
      "#generated using pymatgen\n",
      "data_Cs3LiCl4\n",
      "_symmetry_space_group_name_H-M   'P 1'\n",
      "_cell_length_a   8.40000000\n",
      "_cell_length_b   8.40000000\n",
      "_cell_length_c   4.20000000\n",
      "_cell_angle_alpha   90.00000000\n",
      "_cell_angle_beta   90.00000000\n",
      "_cell_angle_gamma   90.00000000\n",
      "_symmetry_Int_Tables_number   1\n",
      "_chemical_formula_structural   Cs3LiCl4\n",
      "_chemical_formula_sum   'Cs3 Li1 Cl4'\n",
      "_cell_volume   296.352\n",
      "_cell_formula_units_Z   1\n",
      "loop_\n",
      " _symmetry_equiv_pos_site_id\n",
      " _symmetry_equiv_pos_as_xyz\n",
      "  1  'x, y, z'\n",
      "loop_\n",
      " _atom_site_type_symbol\n",
      " _atom_site_label\n",
      " _atom_site_symmetry_multiplicity\n",
      " _atom_site_fract_x\n",
      " _atom_site_fract_y\n",
      " _atom_site_fract_z\n",
      " _atom_site_occupancy\n",
      "  Cs  Cs1  1  0.010000  0.500000  0.000000  1\n",
      "  Cs  Cs2  1  0.500000  0.000000  0.000000  1\n",
      "  Cs  Cs3  1  0.500000  0.500000  0.000000  1\n",
      "  Cl  Cl4  1  0.250000  0.250000  0.500000  1\n",
      "  Cl  Cl5  1  0.250000  0.750000  0.500000  1\n",
      "  Cl  Cl6  1  0.750000  0.250000  0.500000  1\n",
      "  Cl  Cl7  1  0.750000  0.750000  0.500000  1\n",
      "  Li  Li8  1  0.000000  0.000000  0.000000  1\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#Convenient IO to various formats. Format is intelligently determined from file name and extension.\n",
    "structure.to(filename=\"POSCAR\")\n",
    "structure.to(filename=\"CsCl.cif\")\n",
    "\n",
    "#Or if you just supply fmt, you simply get a string.\n",
    "print(structure.to(fmt=\"poscar\"))\n",
    "print(structure.to(fmt=\"cif\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Reading a structure from a file.\n",
    "structure = mg.Structure.from_file(\"POSCAR\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The vaspio_set module provides a means o obtain a complete set of VASP input files for performing calculations. Several useful presets based on the parameters used in the Materials Project are provided."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from pymatgen.io.vaspio_set import MPVaspInputSet\n",
    "v = MPVaspInputSet()\n",
    "v.write_input(structure, \"MyInputFiles\") #Writes a complete set of input files for structure to the directory MyInputFiles"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This concludes this pymatgen tutorial. Please explore the usage pages on pymatgen.org for more information."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
